/**
 *  StaDiUM - State Diagram Unified Modeler
 *  Copyright (C) 2007  Stefan Bucur, Mihai Balan, Claudiu Tanase
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.

 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.

 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

/**
 *  File Information:
 *
 *  Last Modified On: $Date: 2007-06-14 11:06:27 +0000 (Thu, 14 Jun 2007) $
 *  Last Modified By: $Author: stefan.bucur $
 */
package ro.pub.cs.stadium.platform;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import ro.pub.cs.stadium.plugin.IDocumentPlugin;
import ro.pub.cs.stadium.plugin.IInputPlugin;
import ro.pub.cs.stadium.plugin.IOutputPlugin;
import ro.pub.cs.stadium.plugin.IPlugin;
import ro.pub.cs.stadium.plugin.PluginInfo;
import ro.pub.cs.stadium.plugin.PluginSettings;
import ro.pub.cs.stadium.plugin.PluginType;

public class PluginManager implements IPluginProvider{
	private class Plugin {
		public IPlugin loadedPlugin = null;
		public String name = null;
		
		public Plugin() {
			
		}
		
	}
	
	private final MainWindow mainWnd;
	
	private List<Plugin> pluginList = null;
	
	public PluginManager(MainWindow mainWnd) {
		
		this.mainWnd = mainWnd;
		
		pluginList = new LinkedList<Plugin>();
	}
	
	/**
	 * Asynchronously loads a StaDiUM plugin given a Class file
	 * @param pluginClass
	 */
	public IPlugin loadPlugin(final Class pluginClass) throws PluginException {
		IPlugin newPluginInst = null;
		
		try {
			newPluginInst = (IPlugin)pluginClass.newInstance();
		} catch (IllegalAccessException ex) {
			throw new PluginException(ex);
		} catch (InstantiationException ex) {
			throw new PluginException(ex);
		}
		
		Plugin newPlugin = new Plugin();
		newPlugin.loadedPlugin = newPluginInst;
		
		newPlugin.name = getPluginName(newPluginInst);
		
		pluginList.add(newPlugin);
		
		return newPluginInst;
	}
	
	public void initPlugin(IPlugin plugin) {
		PluginSettings plugSett = new PluginSettings();
		
		plugSett.setPluginProvider((IPluginProvider)this);
		plugSett.setSettingsProvider(
				(ISettingsProvider)mainWnd.getSettingsManager());
		
		plugin.initialise(plugSett);
		
		PluginType[] plugTypes = plugin.getPluginImplementations();
		
		for (PluginType crType: plugTypes) {
			if (crType == PluginType.DOCUMENT) {
				IDocumentPlugin docPlugin =
					(IDocumentPlugin)plugin.getPlugin(crType);
				
				docPlugin.registerNewMenus(mainWnd.getMenuManager().getNewMenu());
				docPlugin.registerNewMenus(mainWnd.getToolBarManager().getNewPopupMenu());
			}
		}
	}
	
	/**
	 * 
	 * @return
	 */
	public IDocumentPlugin[] getDocumentPlugins() {
		List<IDocumentPlugin> docPlugins = new ArrayList<IDocumentPlugin>();
		
		for (Plugin crPlugin : pluginList) {
			IDocumentPlugin docPlugin = 
				(IDocumentPlugin)crPlugin.loadedPlugin.getPlugin(PluginType.DOCUMENT);
			
			if (docPlugin != null)
				docPlugins.add(docPlugin);
		}
		
		return docPlugins.toArray(new IDocumentPlugin[0]);
	}
	
	/**
	 * 
	 * @return
	 */
	public IOutputPlugin[] getOutputPlugins() {
		List<IOutputPlugin> outPlugins = new ArrayList<IOutputPlugin>();
		
		for (Plugin crPlugin : pluginList) {
			IOutputPlugin outPlugin =
				(IOutputPlugin)crPlugin.loadedPlugin.getPlugin(PluginType.OUTPUT);
			
			if (outPlugin != null)
				outPlugins.add(outPlugin);
		}
		
		return outPlugins.toArray(new IOutputPlugin[0]);
	}
	
	/**
	 * 
	 * @return
	 */
	public IInputPlugin[] getInputPlugins() {
		List<IInputPlugin> inPlugins = new ArrayList<IInputPlugin>();
		
		for (Plugin crPlugin : pluginList) {
			IInputPlugin inPlugin =
				(IInputPlugin)crPlugin.loadedPlugin.getPlugin(PluginType.INPUT);
			
			if (inPlugin != null)
				inPlugins.add(inPlugin);
		}
		
		return inPlugins.toArray(new IInputPlugin[0]);
	}
	
	/**
	 * 
	 * @return
	 */
	public IPlugin[] getRegisteredPlugins() {
		List<IPlugin> regPlugins = new ArrayList<IPlugin>();
		
		for (Plugin crPlugin : pluginList) {
			regPlugins.add(crPlugin.loadedPlugin);
		}
		
		return regPlugins.toArray(new IPlugin[0]);
	}
	
	/**
	 * 
	 * @param plugin
	 * @return
	 */
	public String getPluginName(IPlugin plugin) {
		if (plugin == null)
			throw new NullPointerException("plugin is null");
		
		PluginInfo pluginInfo = plugin.getPluginInfo();
		
		if (pluginInfo != null) {
			return pluginInfo.getName();
		} else {
			return plugin.getClass().getCanonicalName();
		}	
	}
	
	/**
	 * 
	 * @param plugin
	 * @return
	 */
	public String getPluginTypeName(IPlugin plugin) {
		if (plugin == null)
			throw new NullPointerException("plugin is null");
		
		PluginType[] plugType = plugin.getPluginImplementations();
		
		StringBuffer result = new StringBuffer();
		
		for (int i=0; i < plugType.length; i++) {
			result.append(plugType[i].toString());
			
			if (i < plugType.length - 1) {
				result.append(", ");
			}
		}
		
		return result.toString();
	}

	/* (non-Javadoc)
	 * @see ro.pub.cs.stadium.platform.IPluginProvider#getDocumentPlugin(java.lang.String)
	 */
	public IDocumentPlugin getDocumentPlugin(String docType) {
		if (docType == null)
			throw new NullPointerException("docType parameter is null");
		
		IDocumentPlugin[] docPlugins = getDocumentPlugins();
		
		for (IDocumentPlugin crPlugin : docPlugins) {
			if (docType.equals(crPlugin.getDocumentTypeName()))
				return crPlugin;
		}
		
		return null;
	}
	
	public IOutputPlugin getOutputPlugin(String format) {
		IOutputPlugin[] outPlugins = getOutputPlugins();
		
		for (IOutputPlugin crPlugin : outPlugins) {
			if (format.equals(crPlugin.getDocumentFormat())) {
				return crPlugin;
			}
		}
		
		return null;
	}
	
	
}
